כמה אפשר לקוונטט ?

כמה אפשר לקוונטט ?#

Hide code cell source
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import Audio
from scipy.io import wavfile
Hide code cell source
def plot_waveform(data, fs, cut_t = 0.3):
    display(Audio(data, rate=fs))
    cut_n = int(cut_t * fs)
    fig,axes = plt.subplots(2,1,figsize=(10,10))
    axes[0].plot(data[:cut_n], linewidth=0.3)
    axes[0].set_title('Waveform')
    axes[1].specgram(data, Fs=fs, NFFT=2048, noverlap=1024, cmap='jet',scale='dB',)
    axes[1].set_title('Spectrogram')
    plt.show()
Hide code cell source
def quantize_signal(signal, n_bits):
    """
    Quantizes an input signal in [-1, 1] to n_bits using mid-riser levels,
    then returns the quantized value = nearest_level * (2^n_bits).
    """
    signal = signal/np.max(np.abs(signal))
    # Number of quantization levels
    num_levels = 2 ** n_bits

    # Step 1: Generate the mid-riser levels
    # levels[i] = ( (2*i + 1) / (2^n_bits) ) - 1
    levels = np.array([(2*i + 1) / num_levels - 1 for i in range(num_levels)])

    # Step 2: For each sample, find the nearest level
    # We'll do this in a vectorized way using broadcasting.
    #   1) Expand signal to shape (len(signal), 1)
    #   2) Compute absolute differences to each level
    #   3) Argmin over the level dimension
    signal = np.clip(signal, -1.0, 1.0)  # ensure it's in [-1, 1]
    diffs = np.abs(signal.reshape(-1, 1) - levels.reshape(1, -1))
    indices = np.argmin(diffs, axis=1)

    # Step 3: Map each sample to nearest_level * 2^n_bits
    quantized_levels = levels[indices]       # nearest level
    quantized_output = quantized_levels
    return quantized_output
# Load the data in 16 bits
fs, data = wavfile.read('sounds/jackson5 - 16bit.wav')
normalize_data = data / np.max(np.abs(data))
plot_waveform(normalize_data, fs)
../_images/0173b28c55021b9e3db32fa8eddebc5500704a9a768723647e16526f07c6366a.png
for n_bits in [5,4,3,2,1]:
    print(f"###############################n_bits = {n_bits}###############################")
    quantize_signal_data = quantize_signal(data,n_bits)
    plot_waveform(quantize_signal_data, fs)
###############################n_bits = 5###############################
../_images/e59a68b36e150052a08976963d401cca12c509cc71833f2e42f918912dc651d5.png
###############################n_bits = 4###############################
../_images/151fbadbe3e2ddbf1df3dd22dd7cff88ed76f47c3e7ea93691ecf147b5df0643.png
###############################n_bits = 3###############################
../_images/a6d5ff678c1ed99e80d0316b7e2cce5c55b1aa47f134aa8bb64b73e05ef9d8df.png
###############################n_bits = 2###############################
../_images/d33ed6fcd31afbb9114e577c5920bb439a706272020ad57b1a7494e1024bde4f.png
###############################n_bits = 1###############################
../_images/8724701d31efc564c3d6493a0b71692d8824eef46699b8c2cab032a432b01b94.png
# plot all psd
plt.figure()
for n_bits in [5,4,3,2,1]:
    quantize_signal_data = quantize_signal(data,n_bits)
    # normalize the energy to 1
    quantize_signal_data = quantize_signal_data / np.sqrt(np.mean(np.abs(quantize_signal_data)**2))
    plt.psd(quantize_signal_data, NFFT=4096, Fs=fs, label=f'{n_bits} bits')
plt.legend()
plt.show()
../_images/1e8dcb7a39b9d3daed69b2e458219a5352d90470019aca652ed7ebc774d855c6.png